﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using AIRO.Devices.Solenoid;
using Ivi.ConfigServer.Interop;
using Ivi.SessionFactory.Interop;
using Ivi.Driver.Interop;
using AIRO.Devices.PositioningDevice;
using System.Globalization;


namespace AIRO.GoTo
{
    /// <summary>
    /// The serial state
    /// </summary>
    public enum StateType
    {
        /// <summary>
        /// Application is idle.
        /// </summary>
        Idle,
        /// <summary>
        /// Serial is running.
        /// </summary>
        Running,
        /// <summary>
        /// Serial was cancelled by user request or error occured.
        /// </summary>
        Cancelled,        
        /// <summary>
        /// The program will now exit.
        /// </summary>
        Exit
    }

    public partial class frmMain : Form
    {
        private ISolenoid solenoid;
        private IPositioningDevice positioningDevice;
        private bool isISolenoidActiveInterface=false;
        private IIviSessionFactory sf = new IviSessionFactoryClass();
        Ivi.ConfigServer.Interop.IviConfigStore cs; 
        private string psLogicalName;
        private StateType _state;
        protected NumberFormatInfo numericFormatProvider = new NumberFormatInfo();

        public frmMain()
        {
            InitializeComponent();
            numericFormatProvider.PercentDecimalSeparator = ".";
            numericFormatProvider.CurrencyDecimalSeparator = ".";
        }
        /// <summary>The State property represents the serial state.</summary>
        /// <value>The State property gets/sets the _state data member.</value>
        public StateType State
        {
            get
            {
                return _state;
            }
            set
            {
                if (value==StateType.Running)
                {                
                        //btExit.Enabled = false;
                        cbSolenoid.Enabled = false;
                        tbDesiredField.Enabled = false;
                        rbISolenoid.Enabled = false;
                        btSetStop.Text = "Cancel";
                        if (!isISolenoidActiveInterface)
                        {
                            btSetStop.Enabled = false;
                        }
                }
                else
                {
                        //btExit.Enabled = true;
                        cbSolenoid.Enabled = true;
                        tbDesiredField.Enabled = true;
                        rbISolenoid.Enabled = true;
                        btSetStop.Text = "Move";
                        btSetStop.Enabled = true;  
                }              
                _state = value;
            }
        }
        

        private void btSetStop_Click(object sender, EventArgs e)
        {
            if (_state!=StateType.Running)
            {
                State = StateType.Running;
                double field = System.Convert.ToDouble(tbDesiredField.Text,numericFormatProvider);
                if (isISolenoidActiveInterface)
                {
                    solenoid.BeginGotoField(field);
                }
                else
                {
                    positioningDevice.BeginMove(field);
                }
            }
            else
            {
                if (isISolenoidActiveInterface)
                {
                    solenoid.Cancel();
                    tbCurrentField.Text = solenoid.MagnetField.ToString(numericFormatProvider);
                }                
                State = StateType.Cancelled;               
               
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {              
            cs = new IviConfigStoreClass();            
            string location;
            if (cs.ProcessDefaultLocation != "")
            {
                location = cs.ProcessDefaultLocation;
            }
            else if (cs.MasterLocation != "")
            {
                location = cs.MasterLocation;
            }
            else
            {
                throw new Exception("Process Default Location and Master Location are null strings!");
            }
            cs.Deserialize(location);

            populateDeviceList();
        }

        private void populateDeviceList()
        {
            #region Search for Solenoids and Positioning devices
            cbSolenoid.Items.Clear();
            //string defaultDevice;
            foreach (IviLogicalName logicalName in cs.LogicalNames)
            {
                if (logicalName.Session != null)
                {
                    IviSoftwareModule softwareModule = logicalName.Session.SoftwareModule;

                    if (softwareModule != null)
                    {
                        IviPublishedAPICollection publishedAPIs = softwareModule.PublishedAPIs;
                        string progID = softwareModule.ProgID;
                        Type type = Type.GetTypeFromProgID(progID);
                        if (type != null)
                        {
                            Type requiredInterface;
                            if (isISolenoidActiveInterface)
                            {
                                requiredInterface = typeof(ISolenoid);
                                //defaultDevice = GoTo.Properties.Settings.Default.SolenoidLogicalName;
                            }
                            else
                            {
                                requiredInterface = typeof(IPositioningDevice);
                                //defaultDevice = GoTo.Properties.Settings.Default.PositioningDeviceLogicalName;
                            }
                            foreach (Type tInterface in type.GetInterfaces())
                            {

                                // Является ли этот интерфейс ISolenoid или IPositioningDevice, т.е. тем что мы ищем
                                if (tInterface == requiredInterface)
                                {
                                    //Если да, то добавляем logicalName в список опций
                                    cbSolenoid.Items.Add(logicalName.Name);
                                    /*
                                    if (logicalName.Name == defaultDevice)
                                        cbSolenoid.SelectedItem = defaultDevice;
                                     * */
                                }
                            }
                        }
                    }
                }
            }
            #endregion            
        }

        private void initDevice()
        {
            psLogicalName = cbSolenoid.Text;            
            try
            {
                if (isISolenoidActiveInterface)
                {
                    solenoid = (ISolenoid)sf.CreateDriver(psLogicalName);
                    ((Ivi.Driver.Interop.IIviDriver)solenoid).Initialize(psLogicalName, false, false, "");
                    solenoid.StateChangedEvent += new EventHandler<AIRO.Devices.Solenoid.StateChangedEventArgs>(solenoid_StateChangedEvent);
                    solenoid.ProgressEvent += new EventHandler<AIRO.Devices.Solenoid.ProgressEventArgs>(solenoid_ProgressEvent);
                    solenoid.FieldSetEvent += new EventHandler<AIRO.Devices.Solenoid.FieldSetEventArgs>(solenoid_FieldSetEvent);
                    updateSolenoidState(solenoid.State);
                }
                else
                {
                    positioningDevice = (IPositioningDevice)sf.CreateDriver(psLogicalName);
                    ((Ivi.Driver.Interop.IIviDriver)positioningDevice).Initialize(psLogicalName, false, false, "");
                    positioningDevice.StateChangedEvent += new EventHandler<AIRO.Devices.PositioningDevice.StateChangedEventArgs>(positioningDevice_StateChangedEvent);
                    positioningDevice.ProgressEvent += new EventHandler<AIRO.Devices.PositioningDevice.ProgressEventArgs>(positioningDevice_ProgressEvent);
                    updatePositioningDeviceState(positioningDevice.State);
                    
                }
            }
            catch (Exception e)
            {
                this.Text = cbSolenoid.Text + " [Error]";
                MessageBox.Show(e.Message, "Can not initialize driver!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                btSetStop.Enabled = false;
                return;
            }
            btSetStop.Enabled = true;            
        }

        private void cbSolenoid_SelectedIndexChanged(object sender, EventArgs e)
        {
            closeDevices();
            initDevice();
        }

        private void updateSolenoidState(AIRO.Devices.Solenoid.SolenoidState currentState)
        {           

            switch (currentState)
            {
                case SolenoidState.Idle:
                    State = StateType.Idle;
                    pbFieldStatus.Image = Properties.Resources.green_circle;
                   this.Text = cbSolenoid.Text + " [Idle]";
                    break;
                case SolenoidState.Running:                    
                    pbFieldStatus.Image = Properties.Resources.yellow_circle;
                   this.Text = cbSolenoid.Text + " [Running]";
                    break;
                case SolenoidState.Error:
                case SolenoidState.QuenchDetected:
                    switch (_state)
                    {
                        case StateType.Running:
                            State = StateType.Cancelled;
                            break;
                        default:
                            break;
                    }
                    pbFieldStatus.Image = Properties.Resources.red_circle;
                   this.Text = cbSolenoid.Text + " [Error]";
                    break;
                case SolenoidState.HeatingPersistentSwitch:                    
                    pbFieldStatus.Image = Properties.Resources.red_circle;
                    this.Text = cbSolenoid.Text + " [Heating persistent switch]";
                    break;
                case SolenoidState.Paused:
                    State = StateType.Idle;
                    pbFieldStatus.Image = Properties.Resources.green_circle;
                   this.Text = cbSolenoid.Text + " [Paused]";
                    break;
            }
            tbCurrentField.Text = solenoid.MagnetField.ToString();
        }

        private void updatePositioningDeviceState(AIRO.Devices.PositioningDevice.PositioningDeviceState currentState)
        {            
            switch (currentState)
            {
                case PositioningDeviceState.Idle:
                    State = StateType.Idle;
                    //btSetStop.Enabled = true;
                    //btExit.Enabled = true;
                    pbFieldStatus.Image = Properties.Resources.green_circle;
                    this.Text = cbSolenoid.Text + " [Idle]";
                    break;
                case PositioningDeviceState.Running:
                    //btSetStop.Enabled = false;
                    //btExit.Enabled = false;
                    pbFieldStatus.Image = Properties.Resources.yellow_circle;
                    this.Text = cbSolenoid.Text + " [Running]";
                    break;
                case PositioningDeviceState.Error:                
                    //btSetStop.Enabled = false;
                    //btExit.Enabled = true;
                    switch (_state)
                    {
                        case StateType.Running:
                            State = StateType.Cancelled;
                            break;
                        default:
                            break;
                    }
                    pbFieldStatus.Image = Properties.Resources.red_circle;
                    this.Text = cbSolenoid.Text + " [Error]";
                    break;                
            }
            if (isISolenoidActiveInterface)
            {
                tbCurrentField.Text = solenoid.MagnetField.ToString();
            }
            else
            {
                tbCurrentField.Text = positioningDevice.Position.ToString();
            }
        }

        void solenoid_FieldSetEvent(object sender, AIRO.Devices.Solenoid.FieldSetEventArgs e)
        {
        }

        void solenoid_ProgressEvent(object sender, AIRO.Devices.Solenoid.ProgressEventArgs e)
        {
            if (InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(delegate { updateCurrentField(e.Field); }));
            }
            else
            {
                updateCurrentField(e.Field);
            }

            
        }

        private void updateCurrentField(double b)
        {
            tbCurrentField.Text = b.ToString();
            tbCurrentField.Update();
        }

        void solenoid_StateChangedEvent(object sender, AIRO.Devices.Solenoid.StateChangedEventArgs e)
        {


            if (InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(delegate { updateSolenoidState(e.State); }));
            }
            else
            {
                updateSolenoidState(e.State); 
            }

                       
        }

        void positioningDevice_ProgressEvent(object sender, AIRO.Devices.PositioningDevice.ProgressEventArgs e)
        {
            if (InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(delegate{updateCurrentField(e.Position);}));
            }
            else
            {
                updateCurrentField(e.Position);
            }
        }

        void positioningDevice_StateChangedEvent(object sender, AIRO.Devices.PositioningDevice.StateChangedEventArgs e)
        {
            
            if (InvokeRequired)
            {
                this.BeginInvoke(new MethodInvoker(delegate { updatePositioningDeviceState(e.State); }));
            }
            else
            {
                updatePositioningDeviceState(e.State);
            }

            
        }        

        private void btExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_state == StateType.Running)
                if (MessageBox.Show("Exiting while the serial is running may leave the system in inconsistent state. Do you really want to exit?", "Are you sure?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    e.Cancel = true;
                    return;
                }
            closeDevices();            
        }

        private void closeDevices()
        {
            if (solenoid != null)
            {
                if (((IIviDriver)solenoid).Initialized)
                    ((IIviDriver)solenoid).Close();
            }

            if (positioningDevice != null)
            {
                if (((IIviDriver)positioningDevice).Initialized)
                    ((IIviDriver)positioningDevice).Close();
            }
        }

        private void rbISolenoid_CheckedChanged(object sender, EventArgs e)
        {
            closeDevices();
            btSetStop.Enabled = false;            
            isISolenoidActiveInterface = rbISolenoid.Checked;
            populateDeviceList();
            cbSolenoid.Text = "";
        }

        private void cbSolenoid_TextChanged(object sender, EventArgs e)
        {
            
        }
    }   
}

